/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/** @defgroup unistd Unistd
 * @ingroup libc
 */

#ifndef _UNISTD_H_
#define _UNISTD_H_

#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/sysconf.h>

#ifndef __LITEOS__
#include <bits/lockf.h>
#endif
#include <bits/posix_limits.h>

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */


#define STDIN_FILENO    0
#define STDOUT_FILENO    1
#define STDERR_FILENO    2

#define F_OK 0
#define X_OK 1
#define W_OK 2
#define R_OK 4

#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2

#define _PC_FILESIZEBITS 0
#define _PC_LINK_MAX 1
#define _PC_MAX_CANON 2
#define _PC_MAX_INPUT 3
#define _PC_NAME_MAX 4
#define _PC_PATH_MAX 5
#define _PC_PIPE_BUF 6
#define _PC_2_SYMLINKS 7
#define _PC_ALLOC_SIZE_MIN 8
#define _PC_REC_INCR_XFER_SIZE 9
#define _PC_REC_MAX_XFER_SIZE 10
#define _PC_REC_MIN_XFER_SIZE 11
#define _PC_REC_XFER_ALIGN 12
#define _PC_SYMLINK_MAX 13
#define _PC_CHOWN_RESTRICTED 14
#define _PC_NO_TRUNC 15
#define _PC_VDISABLE 16
#define _PC_ASYNC_IO 17
#define _PC_PRIO_IO 18
#define _PC_SYNC_IO 19

extern char** environ;

extern __noreturn void _exit(int __status);

extern pid_t  fork(void);
extern pid_t  vfork(void);
/**
* @ingroup unistd
*
* @par Description:
* The getpid() function get the process ID of the calling process.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int The getpid() function shall return the process ID of the calling process.
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern pid_t  getpid(void);
extern pid_t  gettid(void) __pure2;
extern pid_t  getpgid(pid_t __pid);
extern int    setpgid(pid_t __pid, pid_t __pgid);
extern pid_t  getppid(void);
extern pid_t  getpgrp(void);
extern int    setpgrp(void);
extern pid_t  getsid(pid_t __pid) __INTRODUCED_IN(21);
extern pid_t  setsid(void);

extern int execv(const char* __path, char* const* __argv);
extern int execvp(const char* __file, char* const* __argv);
extern int execvpe(const char* __file, char* const* __argv, char* const* __envp)
  __INTRODUCED_IN(21);
extern int execve(const char* __file, char* const* __argv, char* const* __envp);
extern int execl(const char* __path, const char* __arg0, ...);
extern int execlp(const char* __file, const char* __arg0, ...);
extern int execle(const char* __path, const char* __arg0, ...);

extern int nice(int __incr);

extern int setuid(uid_t __uid);
extern uid_t getuid(void);
extern int seteuid(uid_t __uid);
extern uid_t geteuid(void);
extern int setgid(gid_t __gid);
extern gid_t getgid(void);
extern int setegid(gid_t __gid);
extern gid_t getegid(void);
extern int getgroups(int __size, gid_t* __list);
extern int setgroups(size_t __size, const gid_t* __list);
extern int setreuid(uid_t __ruid, uid_t __euid);
extern int setregid(gid_t __rgid, gid_t __egid);
extern int setresuid(uid_t __ruid, uid_t __euid, uid_t __suid);
extern int setresgid(gid_t __rgid, gid_t __egid, gid_t __sgid);
extern int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
extern int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
extern char* getlogin(void);

extern long fpathconf(int __fd, int __name);
extern long pathconf(const char* __path, int __name);

/**
* @ingroup unistd
*
* @par Description:
* The access() function shall check the file named by the pathname pointed to by the __path argument
* for accessibility according to the bit pattern contained in __mode.
*
* @param  __path [IN] path of the file which need to be checked.
* @param  __mode [IN] The value of __mode is either the bitwise-inclusive OR of the access permissions to be checked
*                     (R_OK, W_OK, X_OK) or the existence test (F_OK).
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int The access() function shall return 0 upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EACCES</b>: Permission bits of the file mode do not permit the requested access,
* or search permission is denied on a component of the path prefix.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>EFAULT</b>: Bad address.</li>
* <li><b>ENOENT</b>: A component of the path does not exist, or the path is an empty string.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOTDIR</b>: A component of the path is not a directory.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int access(const char* __path, int __mode);
extern int faccessat(int __dirfd, const char* __path, int __mode, int __flags)
  __INTRODUCED_IN(21);
extern int link(const char* __oldpath, const char* __newpath);
extern int linkat(int __olddirfd, const char* __oldpath, int __newdirfd,
                  const char* __newpath, int __flags) __INTRODUCED_IN(21);

/**
* @ingroup unistd
*
* @par Description:
* The unlink() function shall remove a link to file. When the file's link count becomes 0 and no process
* has the file open, the space occupied by the file shall be freed and the file shall no longer be accessible.
* If one or more processes have the file open when the last link is removed, the link shall be removed before unlink() returns,
* but the removal of the file contents shall be postponed until all references to the file are closed.
*
* @param  __path [IN] path of the file which need to be removed, shall not name a directory.
*
* @attention
* <ul>
* <li>If the unlink() function is called to remove a file in /dev, it shall just call the registered unlink hook function
* the file will still alive and won't be removed.</li>
* </ul>
*
* @retval #int Upon successful completion, these functions shall return 0.
* Otherwise, these functions shall return -1 and set errno to indicate the error.
* If -1 is returned, the named file shall not be changed.
*
*
* @par Errors
* <ul>
* <li><b>EACCES</b>: Search permission is denied for a component of the path prefix,
* or write permission is denied on the directory containing the directory entry to be removed,
* or remove a file in /dev which doesn't register the unlink function.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOTEMPTY</b>: unlink a pseudo-file which is functioning as a directory and the directory is not empty.</li>
* <li><b>ENOENT</b>: A component of path does not name an existing file.</li>
* <li><b>EINVAL</b>: The path is not valid.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EISDIR</b>: The path is a directory.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see close | remove | rename | rmdir
* @since Huawei LiteOS V100R001C00
*/
extern int unlink(const char* __path);
extern int unlinkat(int __dirfd, const char* __path, int __flags);

/**
* @ingroup unistd
*
* @par Description:
* The chdir() function shall cause the directory named by the pathname pointed to by the __path argument to become
* the current working directory; that is, the starting point for path searches for pathnames not beginning with '/'.
*
* @param  __path [IN] path of the file which need to be set as the current working directory.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int Upon successful completion, 0 shall be returned.
* Otherwise, -1 shall be returned, the current working directory shall remain unchanged,
* and errno shall be set to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The path is an empty string.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: A component of the path does not exist,
* or length of __path is longer than {PATH_MAX}.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOSPC</b>: Out of memory in ramfs filesystem.</li>
* <li><b>ENOTDIR</b>: A component of the path is not a directory.</li>
* <li><b>EMFILE</b>: Too many open file.</li>
* <li><b>EROFS</b>: The physical drive is write protected with fat filesystem.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see getcwd
* @since Huawei LiteOS V100R001C00
*/
extern int chdir(const char* __path);
extern int fchdir(int __fd);

/**
* @ingroup unistd
*
* @par Description:
* The rmdir() function shall remove a directory whose name is given by path.
* The directory shall be removed only if it is an empty directory.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  Remove directory successful.
* @retval #-1 An error is encountered and remove the directory failed.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The path is a null pointer or an empty string.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: A component of the path does not exist.</li>
* <li><b>EPERM</b>: The path represent a mount point, or the path is neither a directory nor a file.</li>
* <li><b>ENOTEMPTY</b>: The path argument names a directory that is not an empty directory.</li>
* <li><b>ENOTDIR</b>: A component of path names an existing file instead of a directory.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>EROFS</b>: The physical drive is write protected with fat filesystem.</li>
* <li><b>EACCES</b>: The directory entry to be removed resides on a read-only file system, or remove a directory
* in proc.</li>
* <li><b>EBUSY</b>: Remove a root of file system, or the directory is not empty of ramfs.</li>
* <li><b>ENOSYS</b>: The file system doesn't support to rmdir.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see mkdir | remove | rename | unlink
* @since Huawei LiteOS V100R001C00
*/
extern int rmdir(const char* __path);
extern int pipe(int* __pipefd);
#if defined(__USE_GNU)
extern int pipe2(int* __pipefd, int __flags) __INTRODUCED_IN(9);
#endif
extern int chroot(const char* __path);
extern int symlink(const char* __oldpath, const char* __newpath);
extern int symlinkat(const char* __oldpath, int __newdirfd,
                     const char* __newpath) __INTRODUCED_IN(21);
extern ssize_t readlink(const char* __path, char* __buf, size_t __bufsiz);
extern ssize_t readlinkat(int __dirfd, const char* __path, char* __buf,
                          size_t __bufsiz) __INTRODUCED_IN(21);
extern int chown(const char* __path, uid_t __owner, gid_t __group);
extern int fchown(int __fd, uid_t __owner, gid_t __group);
extern int fchownat(int __dirfd, const char* __path, uid_t __owner,
                    gid_t __group, int __flags);
extern int lchown(const char* __path, uid_t __owner, gid_t __group);

/**
* @ingroup unistd
*
* @par Description:
* The getcwd() function shall place an absolute pathname of the current working directory
* in the array pointed to by __buf, and return __buf.
*
* @param __buf  [IN/OUT] Point to an array which place an absolute pathname of the current working directory and return.
* @param __size [IN]     The size in bytes of the character array pointed to by the __buf argument.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #char* Return the __buf argument if upon successful completion.
* @retval #NULL  An error is encountered and the contents of the array pointed to by __buf are undefined.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The __buf is a NULL pointer.</li>
* <li><b>ERANGE</b>: The size argument is smaller than the length of the current working directory name + 1.</li>
* <li><b>ENAMETOOLONG</b>: Use memcpy_s to copy the current working directory name to __buf failed.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see malloc
* @since Huawei LiteOS V100R001C00
*/
extern char* getcwd(char* __buf, size_t __size);

#ifndef __LITEOS__
extern int sync(void);
#else
/**
* @ingroup unistd
*
* @par Description:
* The sync() function shall request that all data in bcache to be transferred to the storage device for disk 0 and 1.
*
* @attention
* <ul>
* <li>The sync() function in liteos can only flush all data in bcache into storage device, but can't flush
* the data in memory, and it shall not return until the system completed that action or until an error is detected.
* But in POSIX, The sync() function shall cause all information in memory that updates file systems to be scheduled
* for writing out to all file systems, and the writing, although scheduled, is not necessarily complete
* upon return from sync().</li>
* <li>The sync() function is only useful for fat filesystem and the bcache shall be enabled,
* other filesystems don't need to sync.</li>
* <li>The sync() function
* </ul>
*
* @retval #void None.
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see fsync
* @since Huawei LiteOS V100R001C00
*/
extern void sync(void);
#endif

/**
* @ingroup unistd
*
* @par Description:
* The close() function shall close a file descriptor, so that it no longer refers to any file and may be reused.
* Any record locks held on the file it was associated with, and owned by the process, are removed.
* If fd is the last copy of a particular file descriptor the resources associated with it are freed;
* if the descriptor was the last reference to a file which has been removed using unlink() the file is deleted.
*
* @param __fd [IN] file descriptor to close.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  close file successful.
* @retval #-1 An error is encountered and close file failed.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a open file descriptor, or value is not within valid range.</li>
* <li><b>ENOENT</b>: Can't find volume in fat or can't find internal node in jffs.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENODEV</b>: The partition of disk can't find.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see dup | fclose | fopen | ioctl | open | unlink
* @since Huawei LiteOS V100R001C00
*/
extern int close(int __fd);

/**
* @ingroup unistd
*
* @par Description:
* The read() function shall attempt to read __count bytes from the file associated with the open file descriptor,
* __fd, into the buffer pointed to by __buf.
*
* @param __fd    [IN]     file descriptor (or socket descriptor) to read from
* @param __buf   [IN/OUT] user-provided to save the data
* @param __count [IN]     The maximum size of the user-provided buffer
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #ssize_t  A positive non-zero number of bytes read on suceess.
* @retval #0        End-of-file.
* @retval #-1       On failure with errno set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support read().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES</b>: The file is a write-only file.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINVAL</b>: __count is greater than {YAFFS_MAX_FILE_SIZE} in yaffs filesystem.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t read(int __fd, void* __buf, size_t __count);

/**
* @ingroup unistd
*
* @par Description:
* The write() function shall attempt to write __count bytes from the buffer pointed to by __buf to the file
* associated with the open file descriptor, __fd.
*
* @param __fd    [IN] file descriptor (or socket descriptor) to write to
* @param __buf   [IN] Data to write
* @param __count [IN] Length of data to write
*
* @attention
* <ul>
* <li>On a regular file or other file capable of seeking, the actual writing of data shall proceed from the position
* in the file indicated by the file offset associated with fildes. Before successful return from write(), the file
* offset shall be incremented by the number of bytes actually written. On a regular file, if the position
* of the last byte written is greater than or equal to the length of the file, the length of the file shall be
* set to this position plus one.</li>
* <li>If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file
* prior to each write and no intervening file modification operation shall occur between changing the file offset
* and the write operation.</li>
* </ul>
*
* @retval #ssize_t  On success, the number of bytes  written are returned (zero indicates nothing was written).
* @retval #-1       On error, -1 is returned, and errno is set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support write().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES/EROFS</b>: The file is a read-only file or the file system is read-only.</li>
* <li><b>EIO</b>: A physical I/O error has occurred.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINTR</b>: The write operation was terminated due to the receipt of a signal, no data was transferred.</li>
* <li><b>ENOSPC</b>: There was no free space remaining on the device containing the file.</li>
* <li><b>EAGAIN</b>: Non-blocking I/O has been selected using O_NONBLOCK and the write would block.</li>
* <li><b>EFBIG</b>: An attempt was made to write a file that exceeds the implementation defined maximum file
* size or the process' file size limit, or to write at a position past the maximum allowed offset.</li>
* <li><b>EINVAL</b>: The current position of file is less than zero.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t write(int __fd, const void* __buf, size_t __count);

/**
* @ingroup unistd
*
* @par Description:
* The dup() function shall duplicate an open file descriptor. It provides an alternative interface
* to the service provided by fcntl() using the F_DUPFD command. The call dup(fildes) shall be equivalent to:
* fcntl(fildes, F_DUPFD, 0);
*
* @param __oldfd [IN] file descriptor to duplicate.
*
* @attention
* <ul>
* <li>The dup() function doesn't support to duplicate a socket descriptor.</li>
* </ul>
*
* @retval #int  A non-negative integer namely the file descriptor shall be returned upon successful completion.
* @retval #-1 An error is encountered and duplicate file descriptor failed.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __oldfd is not a valid open file descriptor, or it is a socket descriptor.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EMFILE</b>: Too many open files and allocate a file descriptor failed.</li>
* <li><b>ENOENT</b>: Can't find the inode by the pathname associated with __oldfd.</li>
* <li><b>ENOSYS</b>: The current file system doesn't support the dup() function.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see close | fcntl | open
* @since Huawei LiteOS V100R001C00
*/
extern int dup(int __oldfd);

/**
* @ingroup unistd
*
* @par Description:
* The dup2() function shall cause the file descriptor __newfd to refer to the same open file description
* as the file descriptor __oldfd and to share any locks, and shall return __newfd.
* If __newfd is already a valid open file descriptor, it shall be closed first, unless __oldfd is equal to __newfd
* in which case dup2() shall return __newfd without closing it.
*
* @attention
* <ul>
* <li>The dup2() function doesn't support to clone a socket descriptor.</li>
* <li>If __newfd is already a valid opend descriptor, it shall be closed first, even if the file system doesn't
* support dup2().</li>
* </ul>
*
* @retval #int  A non-negative integer namely the file descriptor shall be returned upon successful completion.
* @retval #-1 An error is encountered and duplicate file descriptor failed.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __oldfd is not a valid open file descriptor, or it is a socket descriptor.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOENT</b>: Can't find the inode by the pathname associated with __oldfd.</li>
* <li><b>EINTR</b>: The dup2() function was interrupted by a signal.</li>
* <li><b>ENOSYS</b>: The current file system doesn't support the dup() function.</li>
* <li><b>ENODEV</b>: The mount is not healthy or no such device.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see close | fcntl | open
* @since Huawei LiteOS V100R001C00
*/
extern int dup2(int __oldfd, int __newfd);
extern int dup3(int __oldfd, int __newfd, int __flags) __INTRODUCED_IN(21);
extern int fcntl(int __fd, int __cmd, ...);

/**
* @ingroup unistd
*
* @par Description:
* The ioctl() function shall perform a variety of control functions on STREAMS devices.
* For non-STREAMS devices, the functions performed by this call are unspecified.
* The request argument and an optional third argument (with varying type) shall be passed to
* and interpreted by the appropriate part of the STREAM associated with fildes.
* @param  __fd      [IN] An open file descriptor that refers to a device.
* @param  __request [IN] The command selects the control function to be performed and shall depend
*                        on the STREAMS device being addressed.
* @param  ...       [IN] Additional information that is needed by this specific STREAMS device to perform
                         the requested function. The type of arg depends upon the particular control request,
                         but it shall be either an integer or a pointer to a device-specific data structure.
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int The ioctl() function shall return 0 upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The request or arg argument is not valid for this device.</li>
* <li><b>ENOMEM</b>: If any resource allocation fails, ENOMEM is set as errno.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see open | read | write
* @since Huawei LiteOS V100R001C00
*/
extern int ioctl(int __fd, int __request, ...);

/**
* @ingroup unistd
*
* @par Description:
* The fsync() function shall request that all data for the open file descriptor named by fildes is to
* be transferred to the storage device associated with the file described by fildes.
* The nature of the transfer is implementation-defined. The fsync() function shall not return until
* the system has completed that action or until an error is detected.
*
* @param  __fd [IN] An open file descriptor that refers to a device.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int The fsync() function shall return 0 upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The __fd argument is not valid for this device.</li>
* <li><b>ENOENT</b>: The file can't found.</li>
* <li><b>ENODEV</b>: The device is not existed.</li>
* <li><b>EACCES</b>: The file permission is denied.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see sync
* @since Huawei LiteOS V100R001C00
*/
extern int fsync(int __fd);
extern int fdatasync(int __fd) __INTRODUCED_IN(9);

/**
* @ingroup unistd
*
* @par Description:
* The lseek() function shall set the file offset for the open file description associated with the file descriptor
* __fd, as follows:
* If __whence is SEEK_SET, the file offset shall be set to offset bytes.
* If __whence is SEEK_CUR, the file offset shall be set to its current location plus offset.
* If __whence is SEEK_END, the file offset shall be set to the size of the file plus offset.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #off_t The lseek() function shall return the resulting offset,
* as measured in bytes from the beginning of the file upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The whence argument is not a proper value</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see open
* @since Huawei LiteOS V100R001C00
*/
#if defined(__USE_FILE_OFFSET64)
extern off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
#else
extern off_t lseek(int __fd, off_t __offset, int __whence);
#endif

/**
* @ingroup unistd
*
* @par Description:
* The lseek64() function shall set the file offset for the open file description associated with the file descriptor __fd,
* as follows:
* If __whence is SEEK_SET, the file offset shall be set to offset bytes.
* If __whence is SEEK_CUR, the file offset shall be set to its current location plus offset.
* If __whence is SEEK_END, the file offset shall be set to the size of the file plus offset.
*
* @attention
* <ul>
* <li>lseek is used as lseek64()when one compiles with #define __USE_FILE_OFFSET64.</li>
* </ul>
*
* @retval #off64_t The lseek64() function shall return the resulting offset,
* as measured in bytes from the beginning of the file upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The whence argument is not a proper value</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see open
* @since Huawei LiteOS V100R001C00
*/
extern off64_t lseek64(int __fd, off64_t __offset, int __whence);

#if defined(__USE_FILE_OFFSET64)
extern int truncate(const char* __path, off_t __length) __RENAME(truncate64);
extern ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset)
  __RENAME(pread64);
extern ssize_t pwrite(int __fd, const void* __buf, size_t __count,
                      off_t __offset) __RENAME(pwrite64);
extern int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64);
#else
extern int truncate(const char* __path, off_t __length);

/**
* @ingroup unistd
*
* @par Description:
* The pread() function shall be equivalent to read(), except that it shall read from a given position in the file
* without changing the file offset. The first three arguments to pread() are the same as read() with the addition
* of a fourth argument __offset for the desired position inside the file. An attempt to perform a pread() on a file
* that is incapable of seeking shall result in an error.
*
* @param __fd     [IN]     file descriptor (or socket descriptor) to read from
* @param __buf    [IN/OUT] user-provided to save the data
* @param __count  [IN]     The maximum size of the user-provided buffer
* @param __offset [IN]     The file offset
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #ssize_t  A positive non-zero number of bytes read on suceess.
* @retval #0        End-of-file.
* @retval #-1       On failure with errno set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support read().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES</b>: The file is a write-only file.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINVAL</b>: __count is greater than {YAFFS_MAX_FILE_SIZE} in yaffs filesystem.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset);

/**
* @ingroup unistd
*
* @par Description:
* The pwrite() function shall be equivalent to write(), except that it writes into a given position
* and does not change the file offset (regardless of whether O_APPEND is set). The first three arguments to pwrite()
* are the same as write() with the addition of a fourth argument __offset for the desired position inside the file.
* An attempt to perform a pwrite() on a file that is incapable of seeking shall result in an error.
*
* @param __fd     [IN] file descriptor (or socket descriptor) to write to
* @param __buf    [IN] Data to write
* @param __count  [IN] Length of data to write
* @param __offset [IN] The file offset to write from
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #ssize_t  On success, the number of bytes  written are returned (zero indicates nothing was written).
* @retval #-1       On error, -1 is returned, and errno is set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support write().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES/EROFS</b>: The file is a read-only file or the file system is read-only.</li>
* <li><b>EIO</b>: A physical I/O error has occurred.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINTR</b>: The write operation was terminated due to the receipt of a signal, no data was transferred.</li>
* <li><b>ENOSPC</b>: There was no free space remaining on the device containing the file.</li>
* <li><b>EAGAIN</b>: Non-blocking I/O has been selected using O_NONBLOCK and the write would block.</li>
* <li><b>EFBIG</b>: An attempt was made to write a file that exceeds the implementation defined maximum file
* size or the process' file size limit, or to write at a position past the maximum allowed offset.</li>
* <li><b>EINVAL</b>: The current position of file is less than zero.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t pwrite(int __fd, const void* __buf, size_t __count,
                      off_t __offset);

/**
* @ingroup unistd
*
* @par Description:
* The ftruncate() function truncates the file size to the length bytes.
* If  the  file  previously was larger than this size, the extra data is lost.
* If the file previously was shorter, it is extended, and the extended part reads as disk data.
* @attention
* <ul>
* <li>Now only FAT32 support this function.</li>
* </ul>
*
* @retval #int The ftruncate() function shall return 0 upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The length argument was less than 0 or
* The length argument was greater than the maximum file size.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>EACCES</b>: The file permission is denied.</li>
* <li><b>ENODEV</b>: The device is not existed.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see fallocate
* @since Huawei LiteOS V100R001C00
*/
extern int ftruncate(int __fd, off_t __length);
#endif

extern int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);

/**
* @ingroup unistd
*
* @par Description:
* The pread64() function shall be equivalent to read(), except that it shall read from a given position in the file
* without changing the file offset. The first three arguments to pread64() are the same as read() with the addition
* of a fourth argument __offset for the desired position inside the file. An attempt to perform a pread64() on a file
* that is incapable of seeking shall result in an error.
*
* @param __fd     [IN]     file descriptor (or socket descriptor) to read from
* @param __buf    [IN/OUT] user-provided to save the data
* @param __count  [IN]     The maximum size of the user-provided buffer
* @param __offset [IN]     The file offset
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #ssize_t  A positive non-zero number of bytes read on suceess.
* @retval #0        End-of-file.
* @retval #-1       On failure with errno set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support read().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES</b>: The file is a write-only file.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINVAL</b>: __count is greater than {YAFFS_MAX_FILE_SIZE} in yaffs filesystem.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset) __INTRODUCED_IN(21);

/**
* @ingroup unistd
*
* @par Description:
* The pwrite64() function shall be equivalent to write(), except that it writes into a given position
* and does not change the file offset (regardless of whether O_APPEND is set). The first three arguments to pwrite64()
* are the same as write() with the addition of a fourth argument __offset for the desired position inside the file.
* An attempt to perform a pwrite64() on a file that is incapable of seeking shall result in an error.
*
* @param __fd     [IN] file descriptor (or socket descriptor) to write to
* @param __buf    [IN] Data to write
* @param __count  [IN] Length of data to write
* @param __offset [IN] The file offset to write from
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #ssize_t  On success, the number of bytes  written are returned (zero indicates nothing was written).
* @retval #-1       On error, -1 is returned, and errno is set appropriately.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: __fd is not a valid open file descriptor, or the file system doesn't support write().</li>
* <li><b>EFAULT</b>: __buf is outside your accessible address space.</li>
* <li><b>EACCES/EROFS</b>: The file is a read-only file or the file system is read-only.</li>
* <li><b>EIO</b>: A physical I/O error has occurred.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EINTR</b>: The write operation was terminated due to the receipt of a signal, no data was transferred.</li>
* <li><b>ENOSPC</b>: There was no free space remaining on the device containing the file.</li>
* <li><b>EAGAIN</b>: Non-blocking I/O has been selected using O_NONBLOCK and the write would block.</li>
* <li><b>EFBIG</b>: An attempt was made to write a file that exceeds the implementation defined maximum file
* size or the process' file size limit, or to write at a position past the maximum allowed offset.</li>
* <li><b>EINVAL</b>: The current position of file is less than zero.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see  fcntl | ioctl | lseek | open | readv
* @since Huawei LiteOS V100R001C00
*/
extern ssize_t pwrite64(int __fd, const void* __buf, size_t __count,
                        off64_t __offset) __INTRODUCED_IN(21);
/**
* @ingroup unistd
*
* @par Description:
* The ftruncate64() function truncates the file size to the length bytes.
* If  the  file  previously was larger than this size, the extra data is lost.
* If the file previously was shorter, it is extended, and the extended part reads as disk data.
* @attention
* <ul>
* <li>Now only FAT32 support this function.
* ftruncate is used as ftruncate64()when one compiles with #define __USE_FILE_OFFSET64.</li>
* </ul>
*
* @retval #int The ftruncate64() function shall return 0 upon successful completion.
* Otherwise, the function shall return -1 and set errno.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The __fd argument is not a valid open file descriptor.</li>
* <li><b>ENOSYS</b>: The function is not supported.</li>
* <li><b>EINVAL</b>: The length argument was less than 0 or
* The length argument was greater than the maximum file size.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>EACCES</b>: The file permission is denied.</li>
* <li><b>ENODEV</b>: The device is not existed.</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see fallocate
* @since Huawei LiteOS V100R001C00
*/
extern int ftruncate64(int __fd, off64_t __length) __INTRODUCED_IN(21);

extern int pause(void);
extern unsigned int alarm(unsigned int __seconds);

/**
* @ingroup unistd
*
* @par Description:
* The sleep() function shall cause the calling thread to be suspended from execution until either the number of
* realtime seconds specified by the argument __seconds has elapsed or a signal is delivered to the calling thread
* and its action is to invoke a signal-catching function or to terminate the process.
* The suspension time may be longer than requested due to the scheduling of other activity by the system.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0             The requested time has elapsed.
* @retval #unsigned int  An error is encountered in LOS_TaskDelay() and the __seconds shall be returned.
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see nanosleep
* @since Huawei LiteOS V100R001C00
*/
extern unsigned int sleep(unsigned int __seconds);

/**
* @ingroup unistd
*
* @par Description:
* The usleep() function shall cause the calling thread to be suspended from execution until either the number of
* microsecond specified by the argument __usec has elapsed or a signal is delivered to the calling thread
* and its action is to invoke a signal-catching function or to terminate the process.
* The suspension time may be longer than requested due to the scheduling of other activity by the system.
*
* @attention
* <ul>
* <li>If __usec is less than per Millisecond and is not equal to zero,
* the suspended time shall be set to 1 millisecond.</li>
* <li>The realtime to sleep is __usec/1000 millisecond.</li>
* </ul>
*
* @retval #0   The requested time has elapsed.
* @retval #-1  An error is encountered in LOS_TaskDelay().
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see sleep
* @since Huawei LiteOS V100R001C00
*/
extern int usleep(useconds_t __usec);

int gethostname(char* __name, size_t __len);
int sethostname(const char* __name, size_t __len);

extern void* __brk(void* __addr);
extern int brk(void* __addr);
extern void* sbrk(ptrdiff_t __increment);

/* For communication from `gnu_getopt' to the caller.
   When `gnu_getopt' finds an option that takes an argument,
   the argument value is returned here.
   Also, when `ordering' is RETURN_IN_ORDER,
   each non-option ARGV-element is returned here.  */

extern char *optarg;

/* Index in ARGV of the next element to be scanned.
   This is used for communication to and from the caller
   and for communication between successive calls to `gnu_getopt'.

   On entry to `gnu_getopt', zero means this is the first call; initialize.

   When `gnu_getopt' returns -1, this is the index of the first of the
   non-option elements that the caller should itself scan.

   Otherwise, `gnu_optind' communicates from one call to the next
   how much of ARGV has been scanned so far.  */

extern int optind;

/* Callers store zero here to inhibit the error message `gnu_getopt' prints
   for unrecognized options.  */

extern int opterr;

/* Set to an option character which was unrecognized.  */

extern int optopt;

/**
* @ingroup unistd
*
* @par Description:
* getopt() parses command-line arguments.  Its arguments argc and argv are the argument count and array as
* passed to the main() function on program invocation.  An element of argv that starts with
* '-' is an option element. The characters of this element (aside from the initial '-') are option characters.
* If getopt() is called repeatedly, it returns successively each of the option characters from each of the
* option elements.

* If getopt() finds another option character, it returns that character, updating the external variable optind
* and a static variable nextchar sothat the next call to getopt() can resume the scan with the following
* option character or argv-element.
*
* If there are no more option characters, getopt() returns -1. Then optindis the index in argv of
* the first argv-element that is not an option.
*
* The 'optstring' argument is a string containing the legitimate option characters.
* If such a character is followed by a colon, this indicates that the option requires an argument.
* If an argument is required for an option so getopt() places a pointer to the following text in the same
* argv-element, or the text of the following argv-element, in optarg.
*
* @attention
* <ul>
* <li>opterr is not supported and this implementation of getopt() never printfs error messages.</li>
* <li>getopt is NOT threadsafe!</li>
* <li>This version of getopt() does not reset global variables until -1 is returned.
* As a result, your command line parsing loops must call getopt() repeatedly and continue to parse if other errors
* are returned ('?' or ':') until getopt() finally returns -1.(You can also set optind to -1 to force a reset).</li>
* </ul>
*
* @retval #int If an option was successfully found, then getopt() returns the option character.
* If all command-line options have been parsed, then getopt() returns -1.
* If getopt() encounters an option character that was not in optstring, then '?' is returned.
* If getopt() encounters an option with a missing argument, then the return value depends on the
* first character in optstring: if it is ':', then ':' is returned; otherwise '?' is returned.
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
int getopt(int argc, char *const *argv, const char *optstring);

/* Accessor functions intended for use only by external NXFLAT * modules.
The global variables optarg, optind, and optopt cannot * be referenced
directly from external modules. */

char **getoptargp(void); /* Optional argument following option */
int       *getoptindp(void); /* Index into argv */
int       *getoptoptp(void); /* unrecognized option character */


extern int isatty(int __fd);
extern char* ttyname(int __fd);
extern int ttyname_r(int __fd, char* __buf, size_t __buflen) __INTRODUCED_IN(8);

extern int acct(const char* __filepath);

/**
* @ingroup unistd
*
* @par Description:
* The sysconf() function provides a method for the application to determine the current value of
* a configurable system limit or option (variable).
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #long Returns the current variable value on the system
* @retval #-1   The __name is not supported.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>:The __name is not supported</li>
* </ul>
*
* @par Dependency:
* <ul><li>unistd.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
long sysconf(int __name);

#ifndef __LITEOS__
#if __ANDROID_API__ >= 21 /*lint !e553*/
int getpagesize(void);
#else
__inline__ int getpagesize(void) {
  return sysconf(_SC_PAGESIZE);
}
#endif
#else
int getpagesize(void);
#endif

long syscall(long __number, ...);

extern int daemon(int __nochdir, int __noclose);

#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
extern int cacheflush(long __addr, long __nbytes, long __cache);
    /* __attribute__((deprecated("use __builtin___clear_cache instead"))); */
#endif

extern pid_t tcgetpgrp(int __fd);
extern int tcsetpgrp(int __fd, pid_t __pid);

/* Used to retry syscalls that can return EINTR. */
#define TEMP_FAILURE_RETRY(exp) ({         \
    __typeof__(exp) _rc;                   \
    do {                                   \
        _rc = (exp);                       \
    } while (_rc == -1 && errno == EINTR); \
    _rc; })

/* TODO(unified-headers): Factor out all the FORTIFY features. */
extern char* __getcwd_chk(char*, size_t, size_t);
__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
extern char* __getcwd_real(char*, size_t) __RENAME(getcwd);

extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
extern ssize_t __pread_real(int, void*, size_t, off_t) __RENAME(pread);

extern ssize_t __pread64_chk(int, void*, size_t, off64_t, size_t);
__errordecl(__pread64_dest_size_error, "pread64 called with size bigger than destination");
__errordecl(__pread64_count_toobig_error, "pread64 called with count > SSIZE_MAX");
extern ssize_t __pread64_real(int, void*, size_t, off64_t) __RENAME(pread64);

extern ssize_t __pwrite_chk(int, const void*, size_t, off_t, size_t);
__errordecl(__pwrite_dest_size_error, "pwrite called with size bigger than destination");
__errordecl(__pwrite_count_toobig_error, "pwrite called with count > SSIZE_MAX");
extern ssize_t __pwrite_real(int, const void*, size_t, off_t) __RENAME(pwrite);

extern ssize_t __pwrite64_chk(int, const void*, size_t, off64_t, size_t);
__errordecl(__pwrite64_dest_size_error, "pwrite64 called with size bigger than destination");
__errordecl(__pwrite64_count_toobig_error, "pwrite64 called with count > SSIZE_MAX");
extern ssize_t __pwrite64_real(int, const void*, size_t, off64_t) __RENAME(pwrite64);

extern ssize_t __read_chk(int, void*, size_t, size_t);
__errordecl(__read_dest_size_error, "read called with size bigger than destination");
__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
extern ssize_t __read_real(int, void*, size_t) __RENAME(read);

extern ssize_t __write_chk(int, const void*, size_t, size_t);
__errordecl(__write_dest_size_error, "write called with size bigger than destination");
__errordecl(__write_count_toobig_error, "write called with count > SSIZE_MAX");
extern ssize_t __write_real(int, const void*, size_t) __RENAME(write);

extern ssize_t __readlink_chk(const char*, char*, size_t, size_t);
__errordecl(__readlink_dest_size_error, "readlink called with size bigger than destination");
__errordecl(__readlink_size_toobig_error, "readlink called with size > SSIZE_MAX");
extern ssize_t __readlink_real(const char*, char*, size_t) __RENAME(readlink);

extern ssize_t __readlinkat_chk(int dirfd, const char*, char*, size_t, size_t);
__errordecl(__readlinkat_dest_size_error, "readlinkat called with size bigger than destination");
__errordecl(__readlinkat_size_toobig_error, "readlinkat called with size > SSIZE_MAX");
extern ssize_t __readlinkat_real(int dirfd, const char*, char*, size_t) __RENAME(readlinkat);

#if defined(__BIONIC_FORTIFY)

__BIONIC_FORTIFY_INLINE
char* getcwd(char* buf, size_t size) {
    size_t bos = __bos(buf);

#if defined(__clang__)
    /*
     * Work around LLVM's incorrect __builtin_object_size implementation here
     * to avoid needing the workaround in the __getcwd_chk ABI forever.
     *
     * https://llvm.org/bugs/show_bug.cgi?id=23277
     */
    if (buf == NULL) {
        bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
    }
#else
    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __getcwd_real(buf, size);
    }

    if (__builtin_constant_p(size) && (size > bos)) {
        __getcwd_dest_size_error();
    }

    if (__builtin_constant_p(size) && (size <= bos)) {
        return __getcwd_real(buf, size);
    }
#endif

    return __getcwd_chk(buf, size, bos);
}

#if defined(__USE_FILE_OFFSET64)
#define __PREAD_PREFIX(x) __pread64_ ## x
#else
#define __PREAD_PREFIX(x) __pread_ ## x
#endif

__BIONIC_FORTIFY_INLINE
ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
        __PREAD_PREFIX(count_toobig_error)();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __PREAD_PREFIX(real)(fd, buf, count, offset);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __PREAD_PREFIX(dest_size_error)();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __PREAD_PREFIX(real)(fd, buf, count, offset);
    }
#endif

    return __PREAD_PREFIX(chk)(fd, buf, count, offset, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t pread64(int fd, void* buf, size_t count, off64_t offset) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
        __pread64_count_toobig_error();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __pread64_real(fd, buf, count, offset);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __pread64_dest_size_error();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __pread64_real(fd, buf, count, offset);
    }
#endif

    return __pread64_chk(fd, buf, count, offset, bos);
}

#if defined(__USE_FILE_OFFSET64)
#define __PWRITE_PREFIX(x) __pwrite64_ ## x
#else
#define __PWRITE_PREFIX(x) __pwrite_ ## x
#endif

__BIONIC_FORTIFY_INLINE
ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
        __PWRITE_PREFIX(count_toobig_error)();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __PWRITE_PREFIX(dest_size_error)();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
    }
#endif

    return __PWRITE_PREFIX(chk)(fd, buf, count, offset, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
        __pwrite64_count_toobig_error();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __pwrite64_real(fd, buf, count, offset);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __pwrite64_dest_size_error();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __pwrite64_real(fd, buf, count, offset);
    }
#endif

    return __pwrite64_chk(fd, buf, count, offset, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t read(int fd, void* buf, size_t count) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
        __read_count_toobig_error();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __read_real(fd, buf, count);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __read_dest_size_error();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __read_real(fd, buf, count);
    }
#endif

    return __read_chk(fd, buf, count, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t write(int fd, const void* buf, size_t count) {
    size_t bos = __bos0(buf);

#if !defined(__clang__)
    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __write_real(fd, buf, count);
    }

    if (__builtin_constant_p(count) && (count > bos)) {
        __write_dest_size_error();
    }

    if (__builtin_constant_p(count) && (count <= bos)) {
        return __write_real(fd, buf, count);
    }
#endif

    return __write_chk(fd, buf, count, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t readlink(const char* path, char* buf, size_t size) {
    size_t bos = __bos(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
        __readlink_size_toobig_error();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __readlink_real(path, buf, size);
    }

    if (__builtin_constant_p(size) && (size > bos)) {
        __readlink_dest_size_error();
    }

    if (__builtin_constant_p(size) && (size <= bos)) {
        return __readlink_real(path, buf, size);
    }
#endif

    return __readlink_chk(path, buf, size, bos);
}

__BIONIC_FORTIFY_INLINE
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t size) {
    size_t bos = __bos(buf);

#if !defined(__clang__)
    if (__builtin_constant_p(size) && (size > SSIZE_MAX)) {
        __readlinkat_size_toobig_error();
    }

    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
        return __readlinkat_real(dirfd, path, buf, size);
    }

    if (__builtin_constant_p(size) && (size > bos)) {
        __readlinkat_dest_size_error();
    }

    if (__builtin_constant_p(size) && (size <= bos)) {
        return __readlinkat_real(dirfd, path, buf, size);
    }
#endif

    return __readlinkat_chk(dirfd, path, buf, size, bos);
}

#endif /* defined(__BIONIC_FORTIFY) */


#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _UNISTD_H_ */
